﻿using System;
using System.Collections.Generic;
using System.Collections;

namespace MyKeyValueCollection
{
    public class MyKeyValuePairList : IList<MyKeyValuePair>, IDisposable, IEquatable<MyKeyValuePairList>
    {
        #region Enumerator Class

        private class ListIterator : IEnumerator<MyKeyValuePair>
        {
            public ListIterator(MyKeyValuePairCollection collection)
            {
                m_values = collection;
            }

            ~ListIterator()
            {
                Dispose(false);
            }

            #region IEnumerator Implementation

            public bool MoveNext()
            {
                if (++m_position < m_values.Count)
                {
                    MyKeyValuePair[] arr = new MyKeyValuePair[m_values.Count];
                    m_values.CopyTo(arr, 0);
                    m_curMyKeyValuePair = arr[m_position];

                    return true;
                }

                return false;
            }

            public void Reset()
            {
                m_position = -1;
            }

            object IEnumerator.Current
            {
                get { return m_curMyKeyValuePair; }
            }

            MyKeyValuePair IEnumerator<MyKeyValuePair>.Current
            {
                get { return m_curMyKeyValuePair; }
            }

            public void Dispose()
            {
                Dispose(true);
                GC.SuppressFinalize(this);
            }

            private void Dispose(bool disposeManaged)
            {
                if (m_IsDisposed)
                    return;

                if (disposeManaged)
                {
                    ///TODO:
                }

                m_values.Dispose();

                m_IsDisposed = true;
            }

            #endregion

            #region Private Fields

            private MyKeyValuePairCollection m_values;
            private int m_position = -1;
            private MyKeyValuePair m_curMyKeyValuePair = default(MyKeyValuePair);
            private bool m_IsDisposed = false;

            #endregion
        }

        #endregion

        #region Constructors

        /// <summary>
        /// Initializes new empty instance 
        /// </summary>
        public MyKeyValuePairList()
        {
            MyKeyValuePair[] arr = new MyKeyValuePair[0];
            m_collection = new MyKeyValuePairCollection(arr, 0);
            m_capacity = 0;
        }

        /// <summary>
        ///  Initializes new instance with array values
        /// </summary>
        /// <param name="values">Array of MyKeyValuePair</param>
        public MyKeyValuePairList(MyKeyValuePair[] values)
        {
            m_collection = new MyKeyValuePairCollection(values, values.Length);
            m_capacity = values.Length;
        }

        /// <summary>
        /// Initializes new instance with fixed capacity
        /// </summary>
        /// <param name="capacity">Capacity value</param>
        public MyKeyValuePairList(int capacity)
        {
            MyKeyValuePair[] arr = new MyKeyValuePair[0];
            m_collection = new MyKeyValuePairCollection(arr, 0);
            m_capacity = capacity;
        }

        #endregion

        #region Finalizer

        ~MyKeyValuePairList()
        {
            Dispose(false);
        }

        #endregion

        #region Properties

        /// <summary>
        /// Gets amount of elements in list
        /// </summary>
        public int Count
        {
            get
            {
                return m_collection.Count;
            }
        }

        /// <summary>
        /// Gets/Sets list capacity
        /// </summary>
        /// <exception cref="ArgumentOutOfRangeException">if Capacity is set a value that less than Count.</exception>
        public int Capacity
        {
            get
            {
                return m_capacity;
            }
            set
            {
                if (value < Count)
                    throw new ArgumentOutOfRangeException();

                m_capacity = value;
            }
        }

        #endregion

        #region IList<MyKeyValuePair> Implementation

        /// <summary>
        /// Gets element index
        /// </summary>
        /// <param name="item">Element value</param>
        /// <returns>Element index</returns>
        public int IndexOf(MyKeyValuePair item)
        {
            int index = -1;

            MyKeyValuePair[] arr = new MyKeyValuePair[Count];
            CopyTo(arr, 0);

            for (int i = 0; i < Count; i++)
            {
                if (arr[i].Equals(item))
                {
                    index = i;
                    break;
                }
            }

            return index;
        }

        /// <summary>
        /// Inserts an item to the MyKeyValuePairList at the specified index.
        /// </summary>
        /// <param name="index">The zero-based index at which item should be inserted.</param>
        /// <param name="item">The object to insert into the MyKeyValuePairList.</param>
        /// <exception cref="NotSupportedException">The MyKeyValuePairList is read-only.</exception>
        /// <exception cref="ArgumentOutOfRangeException">Index is not a valid index in the MyKeyValuePairList.</exception>
        public void Insert(int index, MyKeyValuePair item)
        {
            if (IsReadOnly)
                throw new NotSupportedException();

            if (index < 0 || index > Count)
                throw new ArgumentOutOfRangeException();

            MyKeyValuePair[] arrSource = new MyKeyValuePair[Count];
            MyKeyValuePair[] arrDestination = new MyKeyValuePair[Count + 1];
            CopyTo(arrSource, 0);

            Array.Copy(arrSource, 0, arrDestination, 0, index);
            arrDestination[index] = item;
            Array.Copy(arrSource, index, arrDestination, index + 1, Count - index);

            m_collection = new MyKeyValuePairCollection(arrDestination, Count + 1);

            if (Count > m_capacity)
                m_capacity = Count;
        }

        /// <summary>
        /// Removes the MyKeyValuePairList item at the specified index.
        /// </summary>
        /// <param name="index">The zero-based index of the item to remove.</param>
        /// <exception cref="NotSupportedException">The MyKeyValuePairList is read-only.</exception>
        /// <exception cref="ArgumentOutOfRangeException">Index is not a valid index in the MyKeyValuePairList.</exception>
        public void RemoveAt(int index)
        {
            if (IsReadOnly)
                throw new NotSupportedException();

            if (index < 0 || index > Count)
                throw new ArgumentOutOfRangeException();

            MyKeyValuePair[] arrSource = new MyKeyValuePair[Count];
            MyKeyValuePair[] arrDestination = new MyKeyValuePair[Count - 1];
            CopyTo(arrSource, 0);

            Array.Copy(arrSource, 0, arrDestination, 0, index);
            Array.Copy(arrSource, index + 1, arrDestination, index, Count - index - 1);

            m_collection = new MyKeyValuePairCollection(arrDestination, Count - 1);
        }

        /// <summary>
        /// Get/Set list element value
        /// </summary>
        /// <param name="index">Element index</param>
        /// <returns>Element value</returns>
        /// <exception cref="ArgumentOutOfRangeException">If element index less than 0 or bigger than list Count</exception>
        public MyKeyValuePair this[int index]
        {
            get
            {
                if (index < 0 || index > Count)
                    throw new ArgumentOutOfRangeException();

                MyKeyValuePair[] arr = new MyKeyValuePair[Count];
                CopyTo(arr, 0);

                return arr[index];
            }
            set
            {
                if (index < 0 || index > Count)
                    throw new ArgumentOutOfRangeException();

                MyKeyValuePair[] arr = new MyKeyValuePair[Count];
                CopyTo(arr, 0);
                arr[index] = value;
                m_collection = new MyKeyValuePairCollection(arr, arr.Length);
            }
        }

        /// <summary>
        /// Adds an item to the MyKeyValuePairList.
        /// </summary>
        /// <param name="item">The object to add to the MyKeyValuePairList.</param>
        /// <exception cref="NotSupportedException">The MyKeyValuePairList is read-only.</exception>
        public void Add(MyKeyValuePair item)
        {
            if (IsReadOnly)
                throw new NotSupportedException();

            MyKeyValuePair[] arr = new MyKeyValuePair[Count + 1];
            CopyTo(arr, 0);
            arr[Count] = item;
            m_collection = new MyKeyValuePairCollection(arr, arr.Length);

            if (Count > m_capacity)
                m_capacity = Count;
        }

        /// <summary>
        /// Removes all items from the MyKeyValuePairList.
        /// </summary>
        /// <exception cref="NotSupportedException">The MyKeyValuePairList is read-only.</exception>
        public void Clear()
        {
            if (IsReadOnly)
                throw new NotSupportedException();

            MyKeyValuePair[] arr = new MyKeyValuePair[0];
            m_collection = new MyKeyValuePairCollection(arr, 0);
        }

        /// <summary>
        /// Determines whether the MyKeyValuePairList contains a specific value.
        /// </summary>
        /// <param name="item">The object to locate in the MyKeyValuePairList.</param>
        /// <returns>True - if item is found in the MyKeyValuePairList; otherwise - False.</returns>
        public bool Contains(MyKeyValuePair item)
        {
            int indexInList = IndexOf(item);

            if (indexInList >= 0)
                return true;

            return false;
        }

        /// <summary>
        /// Copies the elements of the m_collection to an MyKeyValuePair[], starting at a particular MyKeyValuePair[] arrayIndex.
        /// </summary>
        /// <param name="array">The one-dimensional MyKeyValuePair[] that is the destination of the elements copied from m_collection. The MyKeyValuePair[] must have zero-based indexing.</param>
        /// <param name="arrayIndex">The zero-based index in array at which copying begins.</param>
        /// <exception cref="ArgumentNullException">array is null</exception>
        /// <exception cref="ArgumentOutOfRangeException">arrayIndex is less than zero</exception>
        /// <exception cref="ArgumentException">array is multidimensional.-or- The number of elements in the source m_collection is greater than the available space from arrayIndex to the end of the destination array.</exception>
        public void CopyTo(MyKeyValuePair[] array, int arrayIndex)
        {
            m_collection.CopyTo(array, arrayIndex);
        }

        /// <summary>
        /// Gets a value indicating whether the MyKeyValuePairList is read-only.
        /// </summary>
        public bool IsReadOnly
        {
            get { return false; }
        }

        /// <summary>
        ///  Removes the first occurrence of a specific object from the MyKeyValuePairList.
        /// </summary>
        /// <param name="item">The object to remove from the MyKeyValuePairList.</param>
        /// <returns>True - if item was successfully removed from the MyKeyValuePairList; otherwise - False. This method also returns False if item is not found in the original MyKeyValuePairList.</returns>
        public bool Remove(MyKeyValuePair item)
        {
            if (IsReadOnly)
                throw new NotSupportedException();

            int indexInList = IndexOf(item);

            if (indexInList >= 0)
            {
                RemoveAt(indexInList);

                return true;
            }

            return false;
        }

        public new IEnumerator<MyKeyValuePair> GetEnumerator()
        {
            return new ListIterator(this.m_collection);
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return this.GetEnumerator();
        }

        #endregion

        #region IDisposable Implementation

        /// <summary>
        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
        /// </summary>
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        private void Dispose(bool disposeManaged)
        {
            if (m_IsDisposed)
                return;

            if (disposeManaged)
            {
                ///TODO:
            }

            m_collection.Dispose();

            m_IsDisposed = true;
        }

        #endregion

        #region IEquatable<MyKeyValuePairList> Implementation

        /// <summary>
        /// Compares current MyKeyValuePairList with another one on equal
        /// </summary>
        /// <param name="other">Anothe MyKeyValuePairList</param>
        /// <returns>True - if current MyKeyValuePairList and another one are equal, otherwise - False</returns>
        public bool Equals(MyKeyValuePairList other)
        {
            if (other == null || Count != other.Count)
                return false;

            bool rezult = true;

            for (int i = 0; i < Count; i++)
            {
                if (!this[i].Equals(other[i]))
                {
                    rezult = false;
                    break;
                }
            }

            return rezult;
        }

        #endregion

        #region My additional logic

        /// <summary>
        /// Compares current object with MyKeyValuePair array
        /// </summary>
        /// <param name="arr">MyKeyValuePair array</param>
        /// <returns>True - if current MyKeyValuePairList and MyKeyValuePair array are equal, otherwise - False</returns>
        public bool Compare(MyKeyValuePair[] arr)
        {
            if (arr == null)
                throw new ArgumentNullException();

            if (arr.Length != Count)
                return false;

            bool rez = true;
            MyKeyValuePair[] currentArr = new MyKeyValuePair[Count];
            CopyTo(currentArr, 0);

            for (int i = 0; i < arr.Length; i++)
            {
                if (!currentArr[i].Equals(arr[i]))
                {
                    rez = false;
                    break;
                }
            }

            return rez;
        }

        #endregion

        #region Private Fields

        private MyKeyValuePairCollection m_collection;
        private int m_capacity;
        private bool m_IsDisposed = false;

        #endregion
    }
}
